﻿using System.Collections.Generic;
using Eirene.CLI;
using Eirene.CLI.Services;
using Eirene.Core.Model;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Moq.Protected;

namespace Eirene.CLI.UnitTests
{
    /// <summary>
    /// Test the behaviour of Main.
    /// </summary>
    [TestClass()]
    public class MainTest
    {
        private Mock<IWindowsConsole> mockConsole;
        private Mock<ItemContainer> mockItems;
        private Main target;
        
        [TestInitialize]
        public void TestInitialize()
        {
            // MockBehavior is set to strict.
            mockConsole = new Mock<IWindowsConsole>(MockBehavior.Loose);
            mockItems = new Mock<ItemContainer>(MockBehavior.Strict);

            target = new Main();
            target.Console = mockConsole.Object;
            target.Items = mockItems.Object;
        }

        [TestMethod]
        public void AddNewItem_Add_CheckWasCalled()
        {
            mockItems.Setup(x => x.Add(new Item()));

            var consoleIn = new Queue<string>(new string[] { "1", "0" });

            mockConsole.Setup(i => i.WriteLine(It.IsAny<string>()));

             // Set the user's menu choice
            mockConsole.Setup(i => i.ReadLine())
                                .Returns(() => consoleIn.Dequeue());

            target.Console = mockConsole.Object;

            // call the method
            target.AddNewItem();

            // verify that it was called
            mockItems.Verify(x => x.Add(new Item()), Times.Once());
        }

        [TestMethod]
        public void AddNewItem_Add_InvalidMenuChoice()
        {
            mockItems.Setup(x => x.Add(new Item()));

            var consoleIn = new Queue<string>(new string[] { "invalid input", "0" });

            mockConsole.Setup(i => i.WriteError(It.IsRegex(".*" + " is not a valid choice. Please select from the menu" + ".*"))).Verifiable();

            // Set the user's menu choice
            mockConsole.Setup(i => i.ReadLine())
                                .Returns(() => consoleIn.Dequeue());

            //mockConsole.Object.WriteError("TestMethod");
            target.Console = mockConsole.Object;

            // call the method
            target.AddNewItem();

            // verify that it was called
            mockConsole.Verify();
        }

        [TestMethod]
        public void DisplayItemList_Success()
        {
            var expectedItemName = "Sun Hat";
            var expectedColour = "Blue";
            var expectedPrice = 19.95m;
            var expectedOwnerFName = "Mickey";
            var expectedOwnerLName = "Mouse";
            var expectedStatus = "New";

            var newItem = new Item
            {
                ItemName = "Sun Hat",
                Colour = "Blue",
                Price = 19.95m,
                Owners = new List<Owner>() 
						{ 
							new Owner { FirstName=expectedOwnerFName, LastName=expectedOwnerLName } 
						},
                Status = new Status(expectedStatus)
            };

            var container = new ItemContainer();
            container.Add(newItem);

            //check that the console writes out the line of item info.
            mockConsole.Setup(i => i.WriteLine(
                It.Is<string>(
                    arg => arg.Contains(expectedItemName) &&
                           arg.Contains(expectedColour) &&
                           arg.Contains(expectedPrice.ToString()) &&
                           arg.Contains(expectedOwnerFName) &&
                           arg.Contains(expectedOwnerLName) &&
                           arg.Contains(expectedStatus)
                           )))
                .Verifiable();

            target.Console = mockConsole.Object;

            //mockItems.Setup(i => i.Insert(0, newItem));

            mockItems.Protected()
                     .Setup<ItemContainer>("Insert", 0, newItem);

            mockItems.Protected().Setup("Insert", 0, newItem);

            target.DisplayItemList("Test");

            mockConsole.Verify();
        }
    }
}
